home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / demos / GL / curve / spaced.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  24KB  |  1,052 lines

  1. /*
  2.  * Copyright 1991, 1992, 1993, 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.  * Spaced: The Three-D Space Editor
  19.  *
  20.  * spaced.c
  21.  *
  22.  * This file, along with it's include file, spaced.h, contains
  23.  * all necessary routines for Spaced. See the comments in the include
  24.  * file for instructions on hooking it up to your code.
  25.  *
  26.  * Howard Look
  27.  * July, 1989
  28.  * 
  29.  */
  30.  
  31. #include <gl.h>
  32. #include <device.h>
  33. #include <math.h>
  34. #include "spaced.h"
  35.  
  36. #define X 0
  37. #define Y 1
  38. #define Z 2
  39.  
  40. #define XY 2
  41. #define XZ 1
  42. #define YZ 0
  43. #define NONE -1
  44. #define EDGE_PICKED 99
  45.  
  46. /* Prototypes for internal functions */
  47. static void transform_point(
  48.     Coord *, 
  49.     Matrix, 
  50.     Scoord *);
  51. static float find_distance(
  52.     Scoord p[2], 
  53.     Scoord q[2], 
  54.     Scoord r[2]);
  55. static float cos_angle_between(
  56.     Scoord center[2],
  57.     Scoord p1[2],
  58.     Scoord p2[2]);
  59. static float dist(
  60.     Scoord p1[2], 
  61.     Scoord p2[2]);
  62. static void find_close(
  63.     Scoord m[2],
  64.     Scoord p[2], 
  65.     Scoord q[3][2][2],
  66.     short a[2][2],
  67.     int i[3][2],
  68.     int);
  69. static int length(Scoord axis[2][2]);
  70. static Boolean colinear(Scoord axis1[2][2], Scoord axis2[2][2]);
  71.  
  72.  
  73. /* window information */
  74. static long origin_x, origin_y, size_x, size_y;
  75.  
  76. /* Which plane is motion constrained to */
  77. static int plane;
  78. static int edge;
  79.  
  80.  
  81. static Coord initial_origin[3];
  82. static Scoord initial_screen_origin[2];
  83.  
  84. static Boolean line_constrain, plane_constrain, first_time, constraint_ok;
  85.  
  86. static int colinear_threshold = SP_COLINEAR_THRESHOLD;
  87. static int constraint_threshold = SP_CONSTRAINT_THRESHOLD;
  88.  
  89. static Device line_but1 = SP_LINE_BUTTON1;
  90. static Device line_but2 = SP_LINE_BUTTON2;
  91.  
  92. static Device plane_but1 = SP_PLANE_BUTTON1;
  93. static Device plane_but2 = SP_PLANE_BUTTON2;
  94.  
  95.  
  96.  
  97. /*
  98.  * Call this routine when you have completed all desired motion on a
  99.  * given point.
  100.  */
  101. void end_spaced(void)
  102. {
  103.     /* A gratuitous function for future expansion */
  104. }
  105.  
  106.  
  107. /*
  108.  * Call this routine to change any of spaced's parameters from or to
  109.  * their default values. Calling with any parameter == -1 will reset
  110.  * that parameter to its default value.
  111.  *
  112.  * See the file spaced.h for a description of parameters and their
  113.  * default values.
  114.  */
  115. void set_spaced(
  116.     int col_thresh,
  117.     int const_thresh,
  118.     Device line1,
  119.     Device line2,
  120.     Device plane1,
  121.     Device plane2)
  122. {
  123.     if (col_thresh == SP_DEFAULT)
  124.         colinear_threshold = SP_COLINEAR_THRESHOLD;
  125.     else    
  126.         colinear_threshold = col_thresh;
  127.  
  128.     if (const_thresh == SP_DEFAULT)    
  129.         constraint_threshold = SP_CONSTRAINT_THRESHOLD;
  130.     else
  131.         constraint_threshold = const_thresh;
  132.  
  133.     if (line1 == SP_DEFAULT)
  134.         line_but1 = SP_LINE_BUTTON1;
  135.     else
  136.         line_but1 = line1;
  137.         
  138.     if (line2 == SP_DEFAULT)
  139.         line_but1 = SP_LINE_BUTTON1;
  140.     else
  141.         line_but1 = line2;
  142.         
  143.     if (plane1 == SP_DEFAULT)
  144.         plane_but1 = SP_PLANE_BUTTON1;
  145.     else
  146.         plane_but1 = plane1;
  147.         
  148.     if (plane2 == SP_DEFAULT)
  149.         plane_but1 = SP_PLANE_BUTTON2;
  150.     else
  151.         plane_but1 = plane2;
  152.         
  153. }
  154.  
  155.  
  156.  
  157. void start_spaced()
  158. {
  159.     plane = NONE;
  160.     edge = NONE;
  161.     first_time = TRUE;
  162.     constraint_ok = FALSE;
  163. }
  164.  
  165.     
  166.  
  167. /*
  168.  * The main routine. This is what you call to do update the position
  169.  * of a three-d point in world space.
  170.  *
  171.  * M is the matrix that gets your point from its world space into screen
  172.  * space. If you are in single matrix mode, just do a getmatrix and pass
  173.  * it here. If you are in double matrix mode, you will need to multiply
  174.  * the viewing matrix by the projection matrix to get the matrix needed here.
  175.  *
  176.  * origin is the coordinates of the point you wish to move. This routine
  177.  * will modify origin.
  178.  *
  179.  * limits specifies the bounding box that you wish origin to be contained
  180.  * within. It's format is limit[x=0, y=1, z=2][lo=0, hi=1]
  181.  * 
  182.  * See the comments in spaced.h for more implementation information.
  183.  */
  184. int spaced(Matrix M, Coord origin[3], Coord limit[3][2])
  185. {
  186.     /**************
  187.      * Declarations
  188.      **************/
  189.      
  190.     /* endpoint of line in world space projected from mouse pos'n */
  191.     Coord p1[3],p2[3];
  192.  
  193.     /* dummy view object used to find that line using mapw */
  194.     static Object vobj;
  195.  
  196.     /* Dont want to waste time and memory recreating that object */
  197.     static Boolean object_created = FALSE;
  198.  
  199.     /* Mouse pos'n */
  200.     Scoord mouse[2];
  201.  
  202.     /* Screen coords of the point being moved */
  203.     Scoord screen_motion_point[2];
  204.     
  205.     /* Which axes mouse is between[axis 0,1][endpoint 0,1] */
  206.     static short between[2][2];
  207.  
  208.     /* Your basic first-year geometry stuff */
  209.     Coord dx,dy,dz,x_slope,y_slope,z_slope,
  210.             x_int,y_int,z_int,x_proj,x_proj2,y_proj,y_proj2,z_proj,z_proj2;
  211.  
  212.     /* Screen coords of the six axes endpoints
  213.        screen_axis[x,y,z][end 0,1][x,y] */
  214.     Scoord screen_axis[3][2][2];
  215.  
  216.     /* used in finding screen axes */
  217.     Coord temp[3];
  218.  
  219.     /* Is the point inside of the bounding volume ? */
  220.     Boolean within_bounds;
  221.  
  222.     
  223.     /* 
  224.      * which axes to ignore when moving:
  225.      * at corners, ignore 3 of them
  226.      * at edges, ignore 2 of them
  227.      * at wall, ignore 1 of them
  228.      * inside, ignore none
  229.      *
  230.      * ignore[][0] = axis, ignore[1] = endpt */
  231.     int ignore[3][2];
  232.     int ignore_counter = 0;
  233.  
  234.     /* loop variables */
  235.     int i,j;
  236.  
  237.     Scoord temp_axis[2][2];
  238.  
  239.     Boolean at_edge;
  240.  
  241.     /* constraint value to return */
  242.     int constraint_return = SP_NONE;
  243.  
  244.     /***********************
  245.      * Let the code begin...
  246.      ***********************/
  247.  
  248.     /* The mouse be here */
  249.     mouse[0] = getvaluator(MOUSEX);
  250.     mouse[1] = getvaluator(MOUSEY);
  251.  
  252.     /* what the window is like */
  253.     getorigin(&origin_x, &origin_y);
  254.     getsize(&size_x, &size_y);
  255.  
  256.     /* create the dummy view object, if necessary */
  257.     if (! object_created)
  258.     {
  259.         vobj = genobj();
  260.         makeobj(vobj); closeobj();
  261.         object_created = TRUE;
  262.     }
  263.  
  264.     /* use the current world->screen transformation */
  265.     pushmatrix();
  266.         delobj(vobj);
  267.         makeobj(vobj);
  268.             loadmatrix(M); 
  269.         closeobj();
  270.     popmatrix();
  271.  
  272.     /* find the line that the mouse position maps to in world space */
  273.     mapw(vobj, mouse[0]-origin_x, mouse[1]-origin_y,
  274.         &p1[0], &p1[1], &p1[2], &p2[0], &p2[1], &p2[2]);
  275.  
  276.  
  277.     /* find screen coords of the axes */
  278.     for (i=0; i<3; i++)
  279.         for (j=0; j<2; j++)
  280.         {
  281.             temp[0] = origin[0];
  282.             temp[1] = origin[1];
  283.             temp[2] = origin[2];
  284.             temp[i] = limit[i][j];
  285.             transform_point(temp, M, screen_axis[i][j]);            
  286.         }
  287.  
  288.     /* and of the point in motion */
  289.     temp[0] = origin[0];
  290.     temp[1] = origin[1];
  291.     temp[2] = origin[2];
  292.     transform_point(temp, M, screen_motion_point);
  293.  
  294.     /* Check if constraining starts/stops */
  295.     plane_constrain = getbutton(plane_but1) || getbutton(plane_but2);
  296.     line_constrain = getbutton(line_but1) || getbutton(line_but2);
  297.  
  298.     /* Line constraining is more constraining then plane constraining (!) */
  299.     if (line_constrain)
  300.         plane_constrain = FALSE;
  301.     
  302.     /* Only pick a plane once if constraining, every time if not */
  303.     if ((! line_constrain) && (! plane_constrain))
  304.     {
  305.         plane = NONE;
  306.         constraint_ok = FALSE;
  307.         first_time = TRUE;
  308.     }
  309.     
  310.     /* Setup initial constraint conditions */
  311.     if ((line_constrain || plane_constrain) && first_time)
  312.     {
  313.         first_time = FALSE;
  314.         plane = NONE;
  315.         
  316.         initial_screen_origin[0] = screen_motion_point[0];
  317.         initial_screen_origin[1] = screen_motion_point[1];
  318.  
  319.         initial_origin[0] = origin[0];
  320.         initial_origin[1] = origin[1];
  321.         initial_origin[2] = origin[2];
  322.     }
  323.  
  324.  
  325.     /* Check boundary conditions
  326.      * Only do this once if constraining
  327.      */
  328.     if (plane == NONE)
  329.     {
  330.         within_bounds = TRUE;
  331.  
  332.         ignore_counter = 0;
  333.  
  334.         for(i=0; i<3; i++)
  335.             for(j=0; j<2; j++)
  336.                 if (origin[i] == limit[i][j])
  337.                 {
  338.                     within_bounds = FALSE;
  339.                     ignore[ignore_counter][0] = i;
  340.                     ignore[ignore_counter][1] = j;
  341.                     ignore_counter++;
  342.                 }
  343.     }
  344.     at_edge = (ignore_counter >= 2);
  345.  
  346.  
  347.     /* Check if mouse has moved far enough to do constrained motion */
  348.     if ((line_constrain || plane_constrain) &&
  349.         (plane == NONE) &&
  350.         (!constraint_ok))
  351.     {
  352.         temp_axis[0][0] = (Scoord)(mouse[0]);
  353.         temp_axis[0][1] = (Scoord)(mouse[1]);
  354.         
  355.         temp_axis[1][0] = initial_screen_origin[0];
  356.         temp_axis[1][1] = initial_screen_origin[1];
  357.  
  358.         constraint_ok = (length(temp_axis) > SP_CONSTRAINT_THRESHOLD);
  359.     }
  360.     
  361.  
  362.     /* Check for axis colinearity. Ignore shorter of two colinear axes */
  363.     if ((within_bounds) && (plane == NONE))
  364.     {
  365.         if (colinear(screen_axis[0],screen_axis[1]))
  366.             if (length(screen_axis[0]) < length(screen_axis[1]))
  367.             {
  368.                 ignore[ignore_counter][0] = 0;
  369.                 ignore[ignore_counter][1] = 0;
  370.                 ignore_counter++;
  371.                 ignore[ignore_counter][0] = 0;
  372.                 ignore[ignore_counter][1] = 1;
  373.                 ignore_counter++;
  374.             }
  375.             else
  376.             {
  377.                 ignore[ignore_counter][0] = 1;
  378.                 ignore[ignore_counter][1] = 0;
  379.                 ignore_counter++;
  380.                 ignore[ignore_counter][0] = 1;
  381.                 ignore[ignore_counter][1] = 1;
  382.                 ignore_counter++;
  383.             }
  384.         else if (colinear(screen_axis[0],screen_axis[2]))
  385.             if (length(screen_axis[0]) < length(screen_axis[2]))
  386.             {
  387.                 ignore[ignore_counter][0] = 0;
  388.                 ignore[ignore_counter][1] = 0;
  389.                 ignore_counter++;
  390.                 ignore[ignore_counter][0] = 0;
  391.                 ignore[ignore_counter][1] = 1;
  392.                 ignore_counter++;
  393.             }
  394.             else
  395.             {
  396.                 ignore[ignore_counter][0] = 2;
  397.                 ignore[ignore_counter][1] = 0;
  398.                 ignore_counter++;
  399.                 ignore[ignore_counter][0] = 2;
  400.                 ignore[ignore_counter][1] = 1;
  401.                 ignore_counter++;
  402.             }
  403.         else if (colinear(screen_axis[1],screen_axis[2]))
  404.             if (length(screen_axis[1]) < length(screen_axis[2]))
  405.             {
  406.                 ignore[ignore_counter][0] = 1;
  407.                 ignore[ignore_counter][1] = 0;
  408.                 ignore_counter++;
  409.                 ignore[ignore_counter][0] = 1;
  410.                 ignore[ignore_counter][1] = 1;
  411.                 ignore_counter++;
  412.             }
  413.             else
  414.             {
  415.                 ignore[ignore_counter][0] = 2;
  416.                 ignore[ignore_counter][1] = 0;
  417.                 ignore_counter++;
  418.                 ignore[ignore_counter][0] = 2;
  419.                 ignore[ignore_counter][1] = 1;
  420.                 ignore_counter++;
  421.             }
  422.     }
  423.  
  424.     
  425.  
  426.     if ((plane == NONE) && 
  427.         (((! line_constrain) && (! plane_constrain)) ||
  428.          ((line_constrain || plane_constrain) && (constraint_ok))))
  429.     {
  430.                 
  431.         find_close(
  432.         mouse,screen_motion_point,screen_axis,between,ignore,ignore_counter);
  433.  
  434.         if (! at_edge)
  435.         {
  436.             if ((between[0][0] != 0) && (between[1][0] != 0))
  437.                 plane = YZ;
  438.             else if ((between[0][0] != 1) && (between[1][0] != 1))
  439.                 plane = XZ;
  440.             else if ((between[0][0] != 2) && (between[1][0] != 2))
  441.                 plane = XY;
  442.         }
  443.         else
  444.         {
  445.             edge = between[0][0];
  446.             plane = EDGE_PICKED;
  447.         }
  448.     }
  449.  
  450.     /* Compute where the projected mouse position is */
  451.  
  452.     if ((! at_edge)&&(plane == YZ))
  453.     {
  454.         /* Motion in Y-Z plane, X constant
  455.             Find where line hits the x=0 plane
  456.             As always, y = mx + b */
  457.         dx = p2[0] - p1[0];
  458.         
  459.         if (dx != 0.0)
  460.         {
  461.             dy = p2[1] - p1[1];
  462.             dz = p2[2] - p1[2];
  463.  
  464.             y_slope = dy/dx;                
  465.             y_int = p2[1] - y_slope*p2[0]; /* at x = 0 */
  466.             y_proj = y_slope*origin[0] + y_int;
  467.  
  468.             z_slope = dz/dx;
  469.             z_int = p2[2] - z_slope*p2[0];
  470.             z_proj = z_slope*origin[0] + z_int;
  471.         }
  472.         else
  473.         {
  474.             y_proj = p2[1];
  475.             z_proj = p2[2];
  476.         }
  477.             
  478.         if ((! line_constrain) || (line_constrain && between[0][0] == 1) || 
  479.         plane_constrain)
  480.             if (y_proj <= limit[1][0])
  481.                 origin[1] = limit[1][0];
  482.             else if (y_proj >= limit[1][1])
  483.                 origin[1] = limit[1][1];
  484.             else
  485.                 origin[1] = y_proj;
  486.  
  487.         if ((! line_constrain) || (line_constrain && between[0][0] == 2) ||
  488.         plane_constrain)
  489.             if (z_proj <= limit[2][0])
  490.                 origin[2] = limit[2][0];
  491.             else if (z_proj >= limit[2][1])
  492.                 origin[2] = limit[2][1];
  493.             else
  494.                 origin[2] = z_proj;        
  495.     }
  496.     else if ((! at_edge)&&(plane == XZ))
  497.     {
  498.         /* Motion in X-Z plane, Y constant */
  499.             
  500.         dy = p2[1] - p1[1];
  501.  
  502.         if (dy != 0.0)
  503.         {
  504.             dx = p2[0] - p1[0];
  505.             dz = p2[2] - p1[2];
  506.  
  507.             x_slope = dx/dy;
  508.             x_int = p2[0] - x_slope*p2[1]; /* at y = 0 */
  509.             x_proj = x_slope*origin[1] + x_int;
  510.  
  511.             z_slope = dz/dy;
  512.             z_int = p2[2] - z_slope*p2[1];
  513.             z_proj = z_slope*origin[1] + z_int;
  514.         }
  515.         else
  516.         {
  517.             x_proj = p2[0];
  518.             z_proj = p2[2];
  519.         }
  520.  
  521.         if ((! line_constrain) || (line_constrain && between[0][0] == 0) ||
  522.         plane_constrain)
  523.             if (x_proj <= limit[0][0])
  524.                 origin[0] = limit[0][0];
  525.             else if (x_proj >= limit[0][1])
  526.                 origin[0] = limit[0][1];
  527.             else
  528.                 origin[0] = x_proj;
  529.  
  530.         if ((! line_constrain) || (line_constrain && between[0][0] == 2) ||
  531.         plane_constrain)
  532.             if (z_proj <= limit[2][0])
  533.                 origin[2] = limit[2][0];
  534.             else if (z_proj >= limit[2][1])
  535.                 origin[2] = limit[2][1];
  536.             else
  537.                 origin[2] = z_proj;
  538.                                             
  539.     }
  540.     else if ((! at_edge)&&(plane == XY))
  541.     {
  542.         /* Motion in X-Y plane, Z constant */
  543.         
  544.         dz = p2[2] - p1[2];
  545.  
  546.         if (dz != 0.0)
  547.         {
  548.             dx = p2[0] - p1[0];
  549.             dy = p2[1] - p1[1];
  550.  
  551.             x_slope = dx/dz;
  552.             x_int = p2[0] - x_slope*p2[2]; /* at z = 0 */
  553.             x_proj = x_slope*origin[2] + x_int;
  554.  
  555.             y_slope = dy/dz;
  556.             y_int = p2[1] - y_slope*p2[2];
  557.             y_proj = y_slope*origin[2] + y_int;
  558.         }
  559.         else
  560.         {
  561.             x_proj = p2[0];
  562.             y_proj = p2[1];
  563.         }
  564.             
  565.         if ((! line_constrain) || (line_constrain && between[0][0] == 0) ||
  566.         plane_constrain)
  567.             if (x_proj <= limit[0][0])
  568.                 origin[0] = limit[0][0];
  569.             else if (x_proj >= limit[0][1])
  570.                 origin[0] = limit[0][1];
  571.             else
  572.                 origin[0] = x_proj;
  573.     
  574.         if ((! line_constrain) || (line_constrain && between[0][0] == 1) ||
  575.         plane_constrain)
  576.             if (y_proj <= limit[1][0])
  577.                 origin[1] = limit[1][0];
  578.             else if (y_proj >= limit[1][1])
  579.                 origin[1] = limit[1][1];
  580.             else
  581.                 origin[1] = y_proj;
  582.     }
  583.     else if (edge == X)
  584.     {
  585.         float cos_angle,base,hyp,slength,q1[3],q2[3];
  586.         Scoord sdx,sdy,newx,newy;
  587.     
  588.         cos_angle=cos_angle_between(screen_axis[0][0],screen_axis[0][1],mouse);
  589.  
  590.         hyp = dist(screen_axis[0][0],mouse);
  591.         base = hyp * cos_angle;
  592.  
  593.         sdx = screen_axis[0][1][0] - screen_axis[0][0][0];
  594.         sdy = screen_axis[0][1][1] - screen_axis[0][0][1];
  595.         slength = fsqrt((float)(sdx*sdx + sdy*sdy));
  596.         
  597.         newx = (Scoord) ( (float)screen_axis[0][0][0] + 
  598.         ((float)(screen_axis[0][1][0] - screen_axis[0][0][0]))*(base/slength));
  599.  
  600.         newy = (Scoord) ( (float)screen_axis[0][0][1] + 
  601.         ((float)(screen_axis[0][1][1] - screen_axis[0][0][1]))*(base/slength));
  602.  
  603.         mapw(vobj, newx-origin_x, newy-origin_y,
  604.             &q1[0], &q1[1], &q1[2], &q2[0], &q2[1], &q2[2]);
  605.             
  606.         /* in XY plane... */
  607.         
  608.         dz = q2[2] - q1[2];
  609.  
  610.         if (dz != 0.0)
  611.         {
  612.             dx = q2[0] - q1[0];
  613.             dy = q2[1] - q1[1];
  614.  
  615.             x_slope = dx/dz;
  616.             x_int = q2[0] - x_slope*q2[2]; /* at z = 0 */
  617.             x_proj = x_slope*origin[2] + x_int;
  618.  
  619.             y_slope = dy/dz;
  620.             y_int = q2[1] - y_slope*q2[2];
  621.             y_proj = y_slope*origin[2] + y_int;
  622.         }
  623.         else
  624.         {
  625.             x_proj = q2[0];
  626.             y_proj = q2[1];
  627.         }
  628.         
  629.         /* in XZ plane... */
  630.  
  631.         dy = q2[1] - q1[1];
  632.  
  633.         if (dy != 0.0)
  634.         {
  635.             dx = q2[0] - q1[0];
  636.             dz = q2[2] - q1[2];
  637.  
  638.             x_slope = dx/dy;
  639.             x_int = q2[0] - x_slope*q2[1]; /* at y = 0 */
  640.             x_proj2 = x_slope*origin[1] + x_int;
  641.  
  642.             z_slope = dz/dy;
  643.             z_int = q2[2] - z_slope*q2[1];
  644.             z_proj = z_slope*origin[1] + z_int;
  645.         }
  646.         else
  647.         {
  648.             x_proj2 = q2[0];
  649.             z_proj = q2[2];
  650.         }
  651.  
  652.  
  653.         origin[0] = x_proj - ((y_proj - origin[1])*(x_proj -
  654.                     x_proj2)/(y_proj-z_proj));
  655.  
  656.         
  657.         if (origin[0] < limit[0][0])
  658.             origin[0] = limit[0][0];
  659.         else if (origin[0] > limit[0][1])
  660.             origin[0] = limit[0][1];
  661.  
  662.  
  663.             
  664.     }    
  665.     else if (edge == Y)
  666.     {
  667.         float cos_angle,base,hyp,slength,q1[3],q2[3];
  668.         Scoord sdx,sdy,newx,newy;
  669.     
  670.         cos_angle=cos_angle_between(screen_axis[1][0],screen_axis[1][1],mouse);
  671.  
  672.         hyp = dist(screen_axis[1][0],mouse);
  673.         base = hyp * cos_angle;
  674.  
  675.         sdx = screen_axis[1][1][0] - screen_axis[1][0][0];
  676.         sdy = screen_axis[1][1][1] - screen_axis[1][0][1];
  677.         slength = fsqrt((float)(sdx*sdx + sdy*sdy));
  678.         
  679.         newx = (Scoord) ( (float)screen_axis[1][0][0] + 
  680.         ((float)(screen_axis[1][1][0] - screen_axis[1][0][0]))*(base/slength));
  681.  
  682.         newy = (Scoord) ( (float)screen_axis[1][0][1] + 
  683.         ((float)(screen_axis[1][1][1] - screen_axis[1][0][1]))*(base/slength));
  684.  
  685.         mapw(vobj, newx-origin_x, newy-origin_y,
  686.             &q1[0], &q1[1], &q1[2], &q2[0], &q2[1], &q2[2]);
  687.         
  688.         /* in XY plane... */
  689.         
  690.         dz = q2[2] - q1[2];
  691.  
  692.         if (dz != 0.0)
  693.         {
  694.             dx = q2[0] - q1[0];
  695.             dy = q2[1] - q1[1];
  696.  
  697.             x_slope = dx/dz;
  698.             x_int = q2[0] - x_slope*q2[2]; /* at z = 0 */
  699.             x_proj = x_slope*origin[2] + x_int;
  700.  
  701.             y_slope = dy/dz;
  702.             y_int = q2[1] - y_slope*q2[2];
  703.             y_proj = y_slope*origin[2] + y_int;
  704.         }
  705.         else
  706.         {
  707.             x_proj = q2[0];
  708.             y_proj = q2[1];
  709.         }
  710.         
  711.         /* in YZ plane... */
  712.         dx = q2[0] - q1[0];
  713.         
  714.         if (dx != 0.0)
  715.         {
  716.             dy = q2[1] - q1[1];
  717.             dz = q2[2] - q1[2];
  718.  
  719.             y_slope = dy/dx;                
  720.             y_int = q2[1] - y_slope*q2[0]; /* at x = 0 */
  721.             y_proj2 = y_slope*origin[0] + y_int;
  722.  
  723.             z_slope = dz/dx;
  724.             z_int = q2[2] - z_slope*q2[0];
  725.             z_proj = z_slope*origin[0] + z_int;
  726.         }
  727.         else
  728.         {
  729.             y_proj2 = q2[1];
  730.             z_proj = q2[2];
  731.         }
  732.  
  733.         
  734.         origin[1] = y_proj2 - ((z_proj - origin[0])*(y_proj2 -
  735.         y_proj)/(z_proj-x_proj));
  736.         
  737.         if (origin[1] < limit[1][0])
  738.             origin[1] = limit[1][0];
  739.         else if (origin[1] > limit[1][1])
  740.             origin[1] = limit[1][1];
  741.     }
  742.     else if (edge == Z)
  743.     {
  744.         float cos_angle,base,hyp,slength,q1[3],q2[3];
  745.         Scoord sdx,sdy,newx,newy;
  746.     
  747.         cos_angle=cos_angle_between(screen_axis[2][0],screen_axis[2][1],mouse);
  748.  
  749.         hyp = dist(screen_axis[2][0],mouse);
  750.         base = hyp * cos_angle;
  751.  
  752.         sdx = screen_axis[2][1][0] - screen_axis[2][0][0];
  753.         sdy = screen_axis[2][1][1] - screen_axis[2][0][1];
  754.         slength = fsqrt((float)(sdx*sdx + sdy*sdy));
  755.         
  756.         newx = (Scoord) ( (float)screen_axis[2][0][0] + 
  757.         ((float)(screen_axis[2][1][0] - screen_axis[2][0][0]))*(base/slength));
  758.  
  759.         newy = (Scoord) ( (float)screen_axis[2][0][1] + 
  760.         ((float)(screen_axis[2][1][1] - screen_axis[2][0][1]))*(base/slength));
  761.  
  762.         mapw(vobj, newx-origin_x, newy-origin_y,
  763.             &q1[0], &q1[1], &q1[2], &q2[0], &q2[1], &q2[2]);
  764.  
  765.         /* in XZ plane... */
  766.  
  767.         dy = q2[1] - q1[1];
  768.  
  769.         if (dy != 0.0)
  770.         {
  771.             dx = q2[0] - q1[0];
  772.             dz = q2[2] - q1[2];
  773.  
  774.             x_slope = dx/dy;
  775.             x_int = q2[0] - x_slope*q2[1]; /* at y = 0 */
  776.             x_proj = x_slope*origin[1] + x_int;
  777.  
  778.             z_slope = dz/dy;
  779.             z_int = q2[2] - z_slope*q2[1];
  780.             z_proj = z_slope*origin[1] + z_int;
  781.         }
  782.         else
  783.         {
  784.             x_proj = q2[0];
  785.             z_proj = q2[2];
  786.         }
  787.         
  788.         /* in YZ plane... */
  789.         dx = q2[0] - q1[0];
  790.         
  791.         if (dx != 0.0)
  792.         {
  793.             dy = q2[1] - q1[1];
  794.             dz = q2[2] - q1[2];
  795.  
  796.             y_slope = dy/dx;                
  797.             y_int = q2[1] - y_slope*q2[0]; /* at x = 0 */
  798.             y_proj = y_slope*origin[0] + y_int;
  799.  
  800.             z_slope = dz/dx;
  801.             z_int = q2[2] - z_slope*q2[0];
  802.             z_proj2 = z_slope*origin[0] + z_int;
  803.         }
  804.         else
  805.         {
  806.             y_proj = q2[1];
  807.             z_proj2 = q2[2];
  808.         }
  809.  
  810.  
  811.         origin[2] = z_proj2 - ((x_proj - origin[1])*(z_proj2 -
  812.         z_proj)/(x_proj-y_proj));
  813.         
  814.         if (origin[2] < limit[2][0])
  815.             origin[2] = limit[2][0];
  816.         else if (origin[2] > limit[2][1])
  817.             origin[2] = limit[2][1];
  818.             
  819.  
  820.     }
  821.  
  822.  
  823.     if (plane_constrain)
  824.         switch (plane)
  825.         {
  826.             case YZ: constraint_return = SP_YZ_PLANE; break;
  827.             case XZ: constraint_return = SP_XZ_PLANE; break;
  828.             case XY: constraint_return = SP_XY_PLANE; break;
  829.         }
  830.     else if (line_constrain)
  831.         switch (plane)
  832.         {
  833.             case YZ:
  834.                 if (between[0][0] == 2)
  835.                     constraint_return = SP_Z_AXIS;
  836.                 else
  837.                     constraint_return = SP_Y_AXIS;
  838.                 break;
  839.             case XZ:
  840.                 if (between[0][0] == 2)
  841.                     constraint_return = SP_Z_AXIS;
  842.                 else
  843.                     constraint_return = SP_X_AXIS;
  844.                 break;
  845.             case XY:
  846.                 if (between[0][0] == 1)
  847.                     constraint_return = SP_Y_AXIS;
  848.                 else
  849.                     constraint_return = SP_X_AXIS;
  850.                 break;
  851.         }
  852.     return constraint_return;
  853. }
  854.  
  855.  
  856. /* In variable between, returns which two axis the mouse position is
  857.  * between. There are six possible axes, pos and neg for each of x,y,z.
  858.  * The closest axis to the mouse position will be in between[0], and
  859.  * the next closest will be in between[1].
  860.  * 
  861.  * if ignore is set to 0,1 or 2, that axis will be ignore.
  862.  * 
  863.  * Example: if
  864.  *  between[0][0] = 1, between[0][1] = 0
  865.  *  between[1][0] = 2, between[1][1] = 1
  866.  *
  867.  * means that the mouse is between axis 1, endpoint 0 and axis 2, endpoint 1.
  868.  * Translated, the mouse is between the negative Y and positive Z axes,
  869.  * closer to Y.
  870.  */
  871. static void find_close(
  872.     Scoord mouse[2],
  873.     Scoord center[2], 
  874.     Scoord screen_axis[3][2][2], 
  875.     short between[2][2],
  876.     int ignore[3][2],
  877.     int ignore_counter)
  878. {
  879.     short i, j, k;
  880.     float distance,max1,max2;
  881.  
  882.     max1 = max2 = -2.0; /* nothing will ever be less than -1.0 */
  883.  
  884.     /* find distance from mouse vector to the six axes */
  885.     for(i=0;i<3;i++)
  886.         for(j=0;j<2;j++)
  887.         {
  888.             distance = 0.0;
  889.             
  890.             for (k=0; k<ignore_counter; k++)
  891.                 if ((i == ignore[k][0]) && (j == ignore[k][1]))
  892.                     distance = -2.0;
  893.  
  894.             if (distance == 0.0)
  895.                 distance = find_distance(center, mouse, screen_axis[i][j] );
  896.  
  897.             if (distance > max1)
  898.             {
  899.                 between[1][0] = between[0][0];
  900.                 between[1][1] = between[0][1];
  901.  
  902.                 between[0][0] = i;
  903.                 between[0][1] = j;
  904.                 
  905.                 max2 = max1;
  906.                 max1 = distance;
  907.             }
  908.             else if (distance > max2)
  909.             {
  910.                 between[1][0] = i;
  911.                 between[1][1] = j;
  912.                 
  913.                 max2 = distance;
  914.             }
  915.  
  916.         }
  917. }
  918.  
  919.  
  920. /* Returns the length of the axis. */
  921. static int length(Scoord axis[2][2])
  922. {
  923.     int dx,dy;
  924.  
  925.     dx = axis[1][0] - axis[0][0];
  926.     dy = axis[1][1] - axis[0][1];
  927.  
  928.     return ((int)fsqrt((float)(dx*dx + dy*dy)));
  929. }
  930.  
  931.     
  932.  
  933.  
  934. /* Finds the "distance" between the two vectors from center to p1, and
  935.  * center to p2. Actually returns the dot product, normalized 0.0 to 1.0.
  936.  */
  937. static float find_distance(Scoord center[2], Scoord p1[2], Scoord p2[2])
  938. {
  939.     float result,v1[2],v2[2],n1,n2;
  940.  
  941.     v1[0] = (float)p1[0] - (float)center[0];
  942.     v1[1] = (float)p1[1] - (float)center[1];
  943.  
  944.     v2[0] = (float)p2[0] - (float)center[0];
  945.     v2[1] = (float)p2[1] - (float)center[1];
  946.  
  947.     n1 = fsqrt(v1[0]*v1[0] + v1[1]*v1[1]);
  948.     n2 = fsqrt(v2[0]*v2[0] + v2[1]*v2[1]);
  949.  
  950.     result = (v1[0]/n1)*(v2[0]/n2) + (v1[1]/n1)*(v2[1]/n2);
  951.  
  952.     return(result);
  953. }
  954.  
  955. /*
  956. Returns the cosine of angle between the vectors P1 and P2 with common start
  957. point center
  958. */
  959. static float cos_angle_between(Scoord center[2], Scoord p1[2], Scoord p2[2])
  960. {
  961.     float v1[2],v2[2],n1,n2;
  962.  
  963.     v1[0] = (float)p1[0] - (float)center[0];
  964.     v1[1] = (float)p1[1] - (float)center[1];
  965.  
  966.     v2[0] = (float)p2[0] - (float)center[0];
  967.     v2[1] = (float)p2[1] - (float)center[1];
  968.  
  969.     n1 = fsqrt(v1[0]*v1[0] + v1[1]*v1[1]);
  970.     n2 = fsqrt(v2[0]*v2[0] + v2[1]*v2[1]);
  971.  
  972.     return (v1[0]*v2[0] + v1[1]*v2[1])/(n1*n2);
  973. }
  974.  
  975.  
  976. static float dist(Scoord p1[2], Scoord p2[2])
  977. {
  978.     float result,v1[2];
  979.  
  980.     v1[0] = (float)p2[0] - (float)p1[0];
  981.     v1[1] = (float)p2[1] - (float)p1[1];
  982.  
  983.     return fsqrt(v1[0]*v1[0] + v1[1]*v1[1]);
  984. }
  985.     
  986.     
  987.  
  988. /*
  989.  * Takes a world coordinate (x,y,z) and pumps it through tranformation
  990.  * matrix M, returning the screen coordinate in result.
  991.  *
  992.  * Note: One could use feedback to do this, but it turns out to be
  993.  * faster to do it manually.
  994.  */
  995. static void transform_point(Coord *p, Matrix M, Scoord *result)
  996. {
  997.     Coord x,y,z,w,hx,hy;
  998.  
  999.     x = p[0]*M[0][0] + p[1]*M[1][0] + p[2]*M[2][0] + M[3][0];
  1000.     y = p[0]*M[0][1] + p[1]*M[1][1] + p[2]*M[2][1] + M[3][1];
  1001.     z = p[0]*M[0][2] + p[1]*M[1][2] + p[2]*M[2][2] + M[3][2]; 
  1002.     w = p[0]*M[0][3] + p[1]*M[1][3] + p[2]*M[2][3] + M[3][3];
  1003.  
  1004.     /* Homogeneous coords b/w -1 and 1 */
  1005.     hx = x/w;
  1006.     hy = y/w;
  1007.  
  1008.     result[0] = (Scoord)((1.0 + hx)*(Coord)size_x/2.0) + origin_x;
  1009.     result[1] = (Scoord)((1.0 + hy)*(Coord)size_y/2.0) + origin_y;
  1010. }
  1011.  
  1012.  
  1013. /*
  1014.  * Returns TRUE if the two axes are colinear within COLINEAR_THRESHOLD
  1015.  * pixels.
  1016.  *
  1017.  * Finds the distance from endpoint of one two line of other.
  1018.  * Taken from handbook of mathematical tables... p. 159
  1019.  */
  1020. static Boolean colinear(Scoord a1[2][2], Scoord a2[2][2])
  1021. {
  1022.     float dx,dy,m,b,A,B,C,dist1,dist2;
  1023.     
  1024.     dx = (float)(a1[0][0] - a1[1][0]);
  1025.  
  1026.     if (dx == 0.0)
  1027.         dx = 0.0001;
  1028.  
  1029.     dy = (float)(a1[0][1] - a1[1][1]);
  1030.  
  1031.     m = dy/dx; /* slope */
  1032.     b = (float)a1[0][1] - m*(float)a1[0][0]; /* y intercept */
  1033.  
  1034.     A = -m;
  1035.     B = 1.0;
  1036.     C = -b;
  1037.  
  1038.     dist1 = (A*(float)a2[0][0] + B*(float)a2[0][1] + C)/
  1039.             fsqrt(A*A + B*B);
  1040.  
  1041.     dist2 = (A*(float)a2[1][0] + B*(float)a2[1][1] + C)/
  1042.             fsqrt(A*A + B*B);
  1043.  
  1044.     if ((fabs(dist1) < (float)SP_COLINEAR_THRESHOLD) && (fabs(dist2) < (float)SP_COLINEAR_THRESHOLD))
  1045.         return TRUE;
  1046.     else
  1047.         return FALSE;
  1048. }
  1049.  
  1050.  
  1051.  
  1052.